package org.csu.onlineedubackend.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.csu.onlineedubackend.config.AppConfig;
import org.csu.onlineedubackend.dto.ChatResponse;
import org.csu.onlineedubackend.model.AIChatMessage;
import org.csu.onlineedubackend.model.spark.SparkRequest;
import org.csu.onlineedubackend.model.spark.SparkResponse;
import org.csu.onlineedubackend.service.SparkAiService;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j
@Service
@RequiredArgsConstructor
public class SparkAiServiceImpl implements SparkAiService {

    private final AppConfig.SparkApiConfig sparkApiConfig;
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public ChatResponse sendMessage(String userMessage, List<AIChatMessage> history) {
        try {
            // 如果是打招呼或简单问候，直接放行
            String greetingPattern = ".*?(你好|您好|早上好|下午好|晚上好|嗨|hi|hello|hey).*?";
            if (!userMessage.toLowerCase().matches(greetingPattern)) {
                // 判断消息是否与教育学习相关
                String educationKeywords = ".*?(学习|教育|课程|作业|考试|题目|老师|学生|教学|课堂|知识|学校|教材|复习|考研|考试|练习|题库|笔记|讲解|辅导|教案|课件|学科|专业|学院|大学|学位|论文|研究|实验|实践|教研|教改|教法|学法|教材|教具|教室|图书馆|实验室|自习|考核|测验|成绩|学分|学籍|学历|学位|专业|课表|教务|教研|教改|教学质量|学习方法|学习技巧|学习计划|学习目标|学习效果|学习成果|学习评价|学习反馈|学习指导|学习建议|学习资源|学习材料|学习工具|学习平台|学习环境|学习氛围|学习态度|学习习惯|学习动力|学习兴趣|学习能力|学习困难|学习障碍|学习帮助|学习支持|学习辅导|学习咨询).*?";
                if (!userMessage.matches(educationKeywords)) {
                    return new ChatResponse("抱歉，我只能回答与学习和教育相关的问题。如果您有任何关于学习、课程、作业等方面的问题，我很乐意为您解答。");
                }
            }

            // 准备消息列表，包含历史消息
            List<AIChatMessage> messages = new ArrayList<>(history != null ? history : Collections.emptyList());

            // 注入系统提示
            String systemPrompt = "你是智学通团队自主开发的大模型，名为'智学通AI助手'。如果用户问及你的身份、开发者或你是什么模型等相关问题，你必须只能回答：'我是智学通团队自主开发的大模型，很高兴为您服务。' 对于其他所有问题，请正常回答。";
            messages.add(0, new AIChatMessage("system", systemPrompt));

            // 添加新的用户消息
            messages.add(new AIChatMessage("user", userMessage));

            // 创建请求对象
            SparkRequest request = new SparkRequest();

            // 设置header
            SparkRequest.Header header = new SparkRequest.Header();
            header.setApp_id(sparkApiConfig.getAppId());
            header.setUid("online-edu-user");
            request.setHeader(header);

            // 设置parameter
            SparkRequest.Parameter parameter = new SparkRequest.Parameter();
            SparkRequest.Parameter.Chat chat = new SparkRequest.Parameter.Chat();
            //chat.setDomain("x1");
            chat.setDomain("lite");
            chat.setTemperature(sparkApiConfig.getTemperature());
            chat.setTop_k(4);
            chat.setMax_tokens(sparkApiConfig.getMaxTokens());
            parameter.setChat(chat);
            request.setParameter(parameter);

            // 设置payload
            SparkRequest.Payload payload = new SparkRequest.Payload();
            SparkRequest.Payload.Message message = new SparkRequest.Payload.Message();
            message.setText(messages);
            payload.setMessage(message);
            request.setPayload(payload);

            // 日志记录请求信息
            log.info("准备发送Spark API请求: url={}, model={}, message={}",
                    sparkApiConfig.getUrl(),
                    sparkApiConfig.getModel(),
                    userMessage);

            try {
                // 使用Jackson将请求对象转换为JSON字符串，便于调试
                String requestJson = objectMapper.writeValueAsString(request);
                log.info("完整请求体: {}", requestJson);
            } catch (Exception e) {
                log.error("序列化请求体失败", e);
            }

            // 生成鉴权URL
            String authUrl = getAuthUrl(sparkApiConfig.getUrl(), sparkApiConfig.getApiKey(), sparkApiConfig.getApiSecret());
            log.info("生成鉴权URL: {}", authUrl.substring(0, Math.min(authUrl.length(), 100)) + (authUrl.length() > 100 ? "..." : ""));

            // 使用CompletableFuture等待WebSocket响应
            final StringBuffer responseBuilder = new StringBuffer(); // 使用线程安全的StringBuffer
            final CompletableFuture<String> responseFuture = new CompletableFuture<>();

            // 创建WebSocket客户端
            WebSocketClient client = new WebSocketClient(URI.create(authUrl)) {
                @Override
                public void onOpen(ServerHandshake handshakedata) {
                    log.info("WebSocket连接已打开，状态码: {}, 状态信息: {}", handshakedata.getHttpStatus(), handshakedata.getHttpStatusMessage());
                    try {
                        // 发送请求
                        String requestJson = objectMapper.writeValueAsString(request);
                        this.send(requestJson);
                        log.info("WebSocket请求已发送: {}", requestJson);
                    } catch (Exception e) {
                        log.error("发送WebSocket请求失败", e);
                        responseFuture.completeExceptionally(e);
                        this.close();
                    }
                }

                @Override
                public void onMessage(String message) {
                    try {
                        // log.info("收到WebSocket消息: {}", message);
                        SparkResponse response = objectMapper.readValue(message, SparkResponse.class);

                        // 检查是否有错误
                        if (response.getHeader() != null && response.getHeader().getCode() != 0) {
                            String errorMsg = "星火API错误: code=" + response.getHeader().getCode() +
                                    ", message=" + response.getHeader().getMessage();
                            log.error(errorMsg);
                            responseFuture.completeExceptionally(new RuntimeException(errorMsg));
                            this.close();
                            return;
                        }

                        // 提取回复内容
                        if (response.getPayload() != null &&
                                response.getPayload().getChoices() != null &&
                                response.getPayload().getChoices().getText() != null &&
                                !response.getPayload().getChoices().getText().isEmpty()) {

                            String content = response.getPayload().getChoices().getText().get(0).getContent();
                            if (content != null) { // 只拼接非null的内容
                                responseBuilder.append(content);
                            }
                            // log.info("累计回复内容: {}", responseBuilder.toString());
                        }

                        // 检查是否是最后一条消息
                        if (response.getHeader() != null && response.getHeader().getStatus() == 2) {
                            log.info("收到最后一条消息，关闭WebSocket连接");
                            responseFuture.complete(responseBuilder.toString());
                            this.close();
                        }
                    } catch (Exception e) {
                        log.error("处理WebSocket消息失败", e);
                        responseFuture.completeExceptionally(e);
                        this.close();
                    }
                }

                @Override
                public void onClose(int code, String reason, boolean remote) {
                    log.info("WebSocket连接已关闭: code={}, reason={}, remote={}", code, reason, remote);
                    if (!responseFuture.isDone()) {
                        if (responseBuilder.length() > 0) {
                            log.info("WebSocket连接已关闭，但已收到部分响应，返回已收到的内容");
                            responseFuture.complete(responseBuilder.toString());
                        } else {
                            String errorMsg = "WebSocket连接已关闭，但未收到完整响应: " + reason;
                            log.error(errorMsg);
                            responseFuture.completeExceptionally(new RuntimeException(errorMsg));
                        }
                    }
                }

                @Override
                public void onError(Exception ex) {
                    log.error("WebSocket连接错误", ex);
                    if (ex.getMessage() != null) {
                        log.error("WebSocket错误详情: {}", ex.getMessage());
                    }
                    if (ex.getCause() != null) {
                        log.error("WebSocket错误原因: {}", ex.getCause().getMessage());
                    }
                    responseFuture.completeExceptionally(ex);
                    this.close();
                }
            };

            // 连接WebSocket
            client.connect();

            try {
                // 等待响应，设置超时时间
                String result = responseFuture.get(60, TimeUnit.SECONDS); // 60秒超时
                log.info("获取到AI回复: {}", result.substring(0, Math.min(result.length(), 100)) + (result.length() > 100 ? "..." : ""));
                return new ChatResponse(result);
            } catch (Exception e) {
                log.error("等待WebSocket响应超时或失败", e);
                client.close();
                return new ChatResponse("调用星火API失败: " + e.getMessage());
            }

        } catch (Exception e) {
            log.error("调用星火API异常", e);
            return new ChatResponse("调用星火API异常: " + e.getClass().getSimpleName() + ": " + e.getMessage());
        }
    }

    @Override
    public ChatResponse generateCourseIntroduction(String userMessage, List<AIChatMessage> history) {
        try {
            // 准备消息列表，包含历史消息
            List<AIChatMessage> messages = new ArrayList<>(history != null ? history : Collections.emptyList());

            // 注入系统提示
            String systemPrompt = "你是智学通团队自主开发的大模型，名为'智学通AI助手'。如果用户问及你的身份、开发者或你是什么模型等相关问题，你必须只能回答：'我是智学通团队自主开发的大模型，很高兴为您服务。' 对于其他所有问题，请正常回答。";
            messages.add(0, new AIChatMessage("system", systemPrompt));

            // 添加新的用户消息
            messages.add(new AIChatMessage("user", userMessage));

            // 创建请求对象
            SparkRequest request = new SparkRequest();

            // 设置header
            SparkRequest.Header header = new SparkRequest.Header();
            header.setApp_id(sparkApiConfig.getAppId());
            header.setUid("online-edu-user");
            request.setHeader(header);

            // 设置parameter
            SparkRequest.Parameter parameter = new SparkRequest.Parameter();
            SparkRequest.Parameter.Chat chat = new SparkRequest.Parameter.Chat();
            //chat.setDomain("x1");
            chat.setDomain("lite");
            chat.setTemperature(sparkApiConfig.getTemperature());
            chat.setTop_k(4);
            chat.setMax_tokens(sparkApiConfig.getMaxTokens());
            parameter.setChat(chat);
            request.setParameter(parameter);

            // 设置payload
            SparkRequest.Payload payload = new SparkRequest.Payload();
            SparkRequest.Payload.Message message = new SparkRequest.Payload.Message();
            message.setText(messages);
            payload.setMessage(message);
            request.setPayload(payload);

            // 日志记录请求信息
            log.info("准备发送Spark API请求: url={}, model={}, message={}",
                    sparkApiConfig.getUrl(),
                    sparkApiConfig.getModel(),
                    userMessage);

            try {
                // 使用Jackson将请求对象转换为JSON字符串，便于调试
                String requestJson = objectMapper.writeValueAsString(request);
                log.info("完整请求体: {}", requestJson);
            } catch (Exception e) {
                log.error("序列化请求体失败", e);
            }

            // 生成鉴权URL
            String authUrl = getAuthUrl(sparkApiConfig.getUrl(), sparkApiConfig.getApiKey(), sparkApiConfig.getApiSecret());
            log.info("生成鉴权URL: {}", authUrl.substring(0, Math.min(authUrl.length(), 100)) + (authUrl.length() > 100 ? "..." : ""));

            // 使用CompletableFuture等待WebSocket响应
            final StringBuffer responseBuilder = new StringBuffer(); // 使用线程安全的StringBuffer
            final CompletableFuture<String> responseFuture = new CompletableFuture<>();

            // 创建WebSocket客户端
            WebSocketClient client = new WebSocketClient(URI.create(authUrl)) {
                @Override
                public void onOpen(ServerHandshake handshakedata) {
                    log.info("WebSocket连接已打开，状态码: {}, 状态信息: {}", handshakedata.getHttpStatus(), handshakedata.getHttpStatusMessage());
                    try {
                        // 发送请求
                        String requestJson = objectMapper.writeValueAsString(request);
                        this.send(requestJson);
                        log.info("WebSocket请求已发送: {}", requestJson);
                    } catch (Exception e) {
                        log.error("发送WebSocket请求失败", e);
                        responseFuture.completeExceptionally(e);
                        this.close();
                    }
                }

                @Override
                public void onMessage(String message) {
                    try {
                        // log.info("收到WebSocket消息: {}", message);
                        SparkResponse response = objectMapper.readValue(message, SparkResponse.class);

                        // 检查是否有错误
                        if (response.getHeader() != null && response.getHeader().getCode() != 0) {
                            String errorMsg = "星火API错误: code=" + response.getHeader().getCode() +
                                    ", message=" + response.getHeader().getMessage();
                            log.error(errorMsg);
                            responseFuture.completeExceptionally(new RuntimeException(errorMsg));
                            this.close();
                            return;
                        }

                        // 提取回复内容
                        if (response.getPayload() != null &&
                                response.getPayload().getChoices() != null &&
                                response.getPayload().getChoices().getText() != null &&
                                !response.getPayload().getChoices().getText().isEmpty()) {

                            String content = response.getPayload().getChoices().getText().get(0).getContent();
                            if (content != null) { // 只拼接非null的内容
                                responseBuilder.append(content);
                            }
                            // log.info("累计回复内容: {}", responseBuilder.toString());
                        }

                        // 检查是否是最后一条消息
                        if (response.getHeader() != null && response.getHeader().getStatus() == 2) {
                            log.info("收到最后一条消息，关闭WebSocket连接");
                            responseFuture.complete(responseBuilder.toString());
                            this.close();
                        }
                    } catch (Exception e) {
                        log.error("处理WebSocket消息失败", e);
                        responseFuture.completeExceptionally(e);
                        this.close();
                    }
                }

                @Override
                public void onClose(int code, String reason, boolean remote) {
                    log.info("WebSocket连接已关闭: code={}, reason={}, remote={}", code, reason, remote);
                    if (!responseFuture.isDone()) {
                        if (responseBuilder.length() > 0) {
                            log.info("WebSocket连接已关闭，但已收到部分响应，返回已收到的内容");
                            responseFuture.complete(responseBuilder.toString());
                        } else {
                            String errorMsg = "WebSocket连接已关闭，但未收到完整响应: " + reason;
                            log.error(errorMsg);
                            responseFuture.completeExceptionally(new RuntimeException(errorMsg));
                        }
                    }
                }

                @Override
                public void onError(Exception ex) {
                    log.error("WebSocket连接错误", ex);
                    if (ex.getMessage() != null) {
                        log.error("WebSocket错误详情: {}", ex.getMessage());
                    }
                    if (ex.getCause() != null) {
                        log.error("WebSocket错误原因: {}", ex.getCause().getMessage());
                    }
                    responseFuture.completeExceptionally(ex);
                    this.close();
                }
            };

            // 连接WebSocket
            client.connect();

            try {
                // 等待响应，设置超时时间
                String result = responseFuture.get(60, TimeUnit.SECONDS); // 60秒超时
                log.info("获取到AI回复: {}", result.substring(0, Math.min(result.length(), 100)) + (result.length() > 100 ? "..." : ""));
                return new ChatResponse(result);
            } catch (Exception e) {
                log.error("等待WebSocket响应超时或失败", e);
                client.close();
                return new ChatResponse("调用星火API失败: " + e.getMessage());
            }

        } catch (Exception e) {
            log.error("调用星火API异常", e);
            return new ChatResponse("调用星火API异常: " + e.getClass().getSimpleName() + ": " + e.getMessage());
        }
    }

    /**
     * 生成鉴权URL
     */
    private String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
        URI uri = new URI(hostUrl);
        // 时间戳
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        // 拼接
        String preStr = "host: " + uri.getHost() + "\n" +
                "date: " + date + "\n" +
                "GET " + uri.getPath() + " HTTP/1.1";
        // SHA256加密
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));
        // Base64编码
        String sha = Base64.encodeBase64String(hexDigits);
        // 拼接
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                apiKey, "hmac-sha256", "host date request-line", sha);
        // 拼接URL
        String authUrl = hostUrl.replace("wss://", "https://").replace("ws://", "http://");
        String httpUrl = authUrl + "?" +
                "authorization=" + URLEncoder.encode(Base64.encodeBase64String(authorization.getBytes(StandardCharsets.UTF_8)), "UTF-8") +
                "&date=" + URLEncoder.encode(date, "UTF-8") +
                "&host=" + URLEncoder.encode(uri.getHost(), "UTF-8");

        // 将http地址转换为ws地址
        if (hostUrl.startsWith("wss://") || hostUrl.startsWith("ws://")) {
            return httpUrl.replace("https://", "wss://").replace("http://", "ws://");
        }
        return httpUrl;
    }
} 